package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.system.mapper.SysRoleMapper;
import com.zzyl.system.service.ISysRoleService;
import com.zzyl.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 报警规则Service业务层处理
 * 
 * @author baisong
 * @date 2025-10-28
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService
{
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    /**
     * 查询报警规则
     * 
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询报警规则列表
     * 
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
    {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule)
    {
        return save(alertRule) ? 1 : 0;
    }

    /**
     * 修改报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule)
    {
        return updateById(alertRule) ? 1 : 0;
    }

    /**
     * 批量删除报警规则
     * 
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除报警规则信息
     * 
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysRoleMapper roleMapper;
    @Value("${alertRule.roleAdmin}")
    private String admin;
    @Value("${alertRule.roleRepair}")
    private String repair;
    @Autowired
    private IAlertDataService alertDataService;


    /**
     * 预警规则定时任务
     */
    @Override
    public void alertRuleScan() {
        //查询所有规则并判空
        List<AlertRule> list1 = this.list();
        if (CollectionUtil.isEmpty(list1)){
            log.info("未查询到规则");
            return;
        }

        //查询设备数据并判空然后格式化处理
        List values = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_DATA_LATEST);
        if (CollectionUtil.isEmpty(values)){
            log.info("redis中设备上报数据为空");
            return;
        }
        ArrayList<DeviceData> deviceDataList = new ArrayList<>();
        values.forEach(v->{
              String deviceDataJson  =(String) v;
                List<DeviceData> list = JSONUtil.toList(deviceDataJson, DeviceData.class);
            deviceDataList.addAll(list);
        });
        for (DeviceData deviceData : deviceDataList) {
            //先遍历所有上报数据并获取与当前设备相关的规则
            List<AlertRule> allAlertRuleslist = this.lambdaQuery().eq(AlertRule::getProductKey, deviceData.getProductKey())
                    .eq(AlertRule::getStatus, 1).eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                    .eq(AlertRule::getIotId, -1).list();
            List<AlertRule> specificAlertRuleslist = this.lambdaQuery().eq(AlertRule::getProductKey, deviceData.getProductKey())
                    .eq(AlertRule::getStatus, 1).eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                    .eq(AlertRule::getIotId, deviceData.getIotId()).list();
            Set<AlertRule> alertRules = CollUtil.unionDistinct(allAlertRuleslist, specificAlertRuleslist);
            //再判断规则是否为空
                if (CollectionUtil.isEmpty(alertRules)){
                    log.info("此上报数据无适用规则，不进行校验 iotid{}",deviceData.getIotId());
                    continue;
                }
            //先比较上报时间是否过期
            LocalDateTime alarmTime = deviceData.getAlarmTime();
            LocalDateTime now = LocalDateTime.now();
            long between = LocalDateTimeUtil.between(alarmTime, now, ChronoUnit.SECONDS);
            long abs = Math.abs(between);
            long timeOut=60*60;
                if (between>timeOut){
                    log.info("上报数据过久已超时{}秒，过期时间为{}秒",between,timeOut);
                    continue;
                }
            for (AlertRule alertRule : alertRules) {
                //判断是否在生效时间内
                String alertEffectivePeriod = alertRule.getAlertEffectivePeriod();
                String[] split = alertEffectivePeriod.split("~");
                LocalTime startTime = LocalTime.parse(split[0]);
                LocalTime endTime = LocalTime.parse(split[1]);
                LocalTime localAlarmTime = alarmTime.toLocalTime();
                if (localAlarmTime.isBefore(startTime)||localAlarmTime.isAfter(endTime)){
                    log.info("上报数据时间未在规则校验时间内，不予处理iotid:{},fuctionid:{}",deviceData.getIotId(),deviceData.getFunctionId());
                    continue;
                }
                //在比较设备数据是否超过阈值
                Double dataValue =Double.valueOf(deviceData.getDataValue()) ;
                Double value = Double.valueOf(alertRule.getValue());
                String operator = alertRule.getOperator();
                if ((operator==">="&&dataValue<value)||(operator=="<"&&dataValue>=value)){
                    log.info("上报数据未达到阈值，不做处理,上报值{},阈值{}",dataValue,value);
                    continue;
                }
                //再比较当前时间是否处于沉默周期
                String silentKey = CharSequenceUtil.format(CacheConstants.IOT_ALERT_SILENT_PREFIX,deviceData.getIotId(),deviceData.getFunctionId(),alertRule.getAlertRuleName());
                String silent =(String) redisTemplate.opsForValue().get(silentKey);
                if (StrUtil.isNotBlank(silent)){
                    Long ttl = redisTemplate.getExpire(silentKey, TimeUnit.SECONDS);
                    log.info("此规则仍在沉默时间，沉默时间还有秒");
                    continue;
                }
                //再比较次数是否达到持续周期
                String countKey=CharSequenceUtil.format(CacheConstants.IOT_ALERT_COUNT_PREFIX,deviceData.getIotId(),deviceData.getFunctionId(),alertRule.getAlertRuleName());
                Long increment = redisTemplate.opsForValue().increment(countKey);
                if (increment<alertRule.getDuration()){
                    log.info("当前触发次数小于持续周期，暂不处理，当前次数{}，持续周期次数{}",increment,alertRule.getDuration());
                    continue;
                }
                redisTemplate.delete(countKey);
                List<Long> longs = new ArrayList<>();
                List<Long> longs2 = new ArrayList<>();
                if (alertRule.getAlertDataType()==0){
                    if (deviceData.getLocationType()==0) {
                       longs = deviceMapper.getNursingIdsByIotIdMove(deviceData.getIotId());
                    }else {
                        longs=  deviceMapper.getNursingIdsByIotIdFixed(deviceData.getIotId());
                    }

                }else {
                    longs =roleMapper.getUserIdsByRoleName(repair);
                }
                longs2 =roleMapper.getUserIdsByRoleName(admin);
                System.out.println(longs2);
                longs.addAll(longs2);
                List<Long> collect = longs.stream().distinct().collect(Collectors.toList());
                AlertData bean = BeanUtil.toBean(deviceData, AlertData.class);
                bean.setId(null);
                bean.setAlertRuleId(alertRule.getId());
                String reasonTemplate = "功能{}{}{}，持续了{}个周期才报警，沉默周期：{}分钟";
                String reason = CharSequenceUtil.format(reasonTemplate, alertRule.getFunctionName(), alertRule.getOperator()
                        , alertRule.getValue(), alertRule.getDuration(), alertRule.getAlertSilentPeriod());
                bean.setAlertReason(reason);
                bean.setType(alertRule.getAlertDataType());
                bean.setStatus(0);
                ArrayList<AlertData> alertData = new ArrayList<>();
                for (Long l : collect) {
                    AlertData bean1 = BeanUtil.toBean(bean, AlertData.class);
                    bean1.setUserId(l);
                    alertData.add(bean1);
                }
                alertDataService.saveBatch(alertData);
                redisTemplate.opsForValue().set(silentKey,"46",alertRule.getAlertSilentPeriod(),TimeUnit.MINUTES);

            }


        }




    }
}
